package com.znf4.lucene;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.TrackingIndexWriter;
import org.apache.lucene.search.ControlledRealTimeReopenThread;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.SearcherFactory;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.znf4.constants.CommonConst;

/**
 * 通用类设计，其中包含索通用的常量以及一些通用的方法。
 */
public class IndexManager {

	/**
	 * 索引库路径
	 */
	private static IndexWriter indexWriter;
	private static IndexReader indexReader;
	private static IndexSearcher indexSearcher;
	private static Analyzer analyzer;

	private static TrackingIndexWriter trackingIndexWriter = null ;
    @SuppressWarnings("rawtypes")
	private static ControlledRealTimeReopenThread  searcherManagerReopenThread ;  // 管理类的线程类
	private static IndexCommitThread  indexCommitThread ;  // 将 索引写入硬盘的线程 ， 自己写的线程类
	private static SearcherManager  searcherManager ;  // 检索管理类
	private static final IndexManager  indexManager = new IndexManager() ;  
	
	
	static{
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				if (indexWriter!=null) {
					try {
						indexWriter.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				if (indexReader != null) {
					try {
						indexReader.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});
	}

	/**
	 * 获得IndexWriter对象
	 * <p>Title: getIndexWriter</p>
	 * <p>Description: </p>
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public static IndexWriter getIndexWriter() {
		if (indexWriter != null) {
			return indexWriter;
		}
		try {
			Directory dir = FSDirectory.open(new File( CommonConst.IndexPath ));
			//判断是否以及指定分词器，如未指定使用默认分词器
			Analyzer analyzer = getAnalyzer();
			//创建IndexWriter的配置
			IndexWriterConfig config  = new IndexWriterConfig(Version.LATEST, analyzer);
			System.out.println("判断索引是否 是打开状态的。不是将其打开");	
		    // 判断索引是否 是打开状态的。不是将其打开
			if(IndexWriter.isLocked(dir)){
		    	IndexWriter.unlock(dir);
		    }
			
			indexWriter = new IndexWriter(dir, config);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		/****新添加的内容******/
		trackingIndexWriter = new TrackingIndexWriter(indexWriter) ;
		try {   // 创建索引的管理类
			searcherManager = new SearcherManager(indexWriter , true ,  new SearcherFactory()) ;
		} catch (IOException e) {
			e.printStackTrace();
		}  
		
		//启动线程
		if(null != indexManager){
			indexManager.setThread();
		}
		
		
		return indexWriter;
	}
	
	/**
	 * 获得索引读取对象
	 * <p>Title: getIndexReader</p>
	 * <p>Description: </p>
	 * @return
	 */
	public static IndexReader getIndexReader() {
		if (indexReader != null) {
			return indexReader;
		}
		try {
			File path = new File(CommonConst.IndexPath);    // 
			if (!path.exists()) {
				if (path.isDirectory()) {
					path.mkdirs();
				}
			}
			Directory dir = FSDirectory.open(path);
			indexReader = DirectoryReader.open(dir);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return indexReader;
	}
	/**
	 * 索引查询对象
	 * <p>Title: getIndexSearcher</p>
	 * <p>Description: </p>
	 * @return
	 */
	public static IndexSearcher getIndexSearcher() {
		if (indexSearcher != null ) {
			return indexSearcher;
		}
		indexSearcher = new IndexSearcher(getIndexReader());
		
		return indexSearcher;

	}


	/**
	 * 指定分词器
	 * <p>Title: setAnalyzer</p>
	 * <p>Description: </p>
	 * @param analyzer
	 */
	public static void setAnalyzer(Analyzer analyzer) {
		IndexManager.analyzer = analyzer;
		//更改解析器后重新初始化IndexWriter
		if (indexWriter != null) {
			try {
				indexWriter.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			indexWriter = null;
		}
		//更改解析器后重新初始化IndexReader
		if (indexReader != null) {
			try {
				indexReader.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			indexReader = null;
		}
	}
	
	public static Analyzer getAnalyzer() {
		return analyzer==null ? analyzer = new IKAnalyzer():analyzer;
	}
	
	
	/**
	 * 分词器测试
	 * <p>Title: analyzerToken</p>
	 * <p>Description: </p>
	 */
	public static void analyzerToken(Analyzer analyzer, String text) {
		System.out.println("测试分词器：" + analyzer.getClass().getSimpleName());
		try {
			TokenStream tokenStream = analyzer.tokenStream("content", text);
//			tokenStream.addAttribute(CharTermAttribute.class);
			tokenStream.reset();
			while (tokenStream.incrementToken()) {
				CharTermAttribute attribute = tokenStream.getAttribute(CharTermAttribute.class);
				System.out.println(attribute.toString());
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
	
	/**************************自己添加的内容*****************************/
	
	//启动线程
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private  void setThread(){
		IndexManager.searcherManagerReopenThread = new ControlledRealTimeReopenThread(trackingIndexWriter, searcherManager,CommonConst.IndexReopenMaxStaleSec, CommonConst.IndexReopenMinStaleSec ) ;
		//设置线程名字
		IndexManager.searcherManagerReopenThread.setName("SercherManager  Reopen  thread");
	    // 设置成守护线程
		IndexManager.searcherManagerReopenThread.setDaemon(true);
		// 启动线程
		IndexManager.searcherManagerReopenThread.start();  
		
		// 实例化将 索引写入到硬盘中的线程类对象 PS: 自己定义的线程类
		IndexManager.indexCommitThread = new IndexCommitThread(CommonConst.IndexName + "index commit thread") ;
        // 设置成守护线程
		IndexManager.indexCommitThread.setDaemon(true); 
		IndexManager.indexCommitThread.start(); 
	
	}
		
		
		
	//内部类 讲内存中的内容写入到硬盘中
	private  class  IndexCommitThread extends Thread{
		
		private boolean flag = false ;
		public IndexCommitThread(String name ){
			super(name) ;
		}
		
		@SuppressWarnings("deprecation")
		@Override
		public void run() {
			flag = true ;
			while(flag){
				
				try {
					indexWriter.commit(); 
		System.out.println("索引线程在执行--" + new Date().toLocaleString() + "\t" + CommonConst.IndexName);
					TimeUnit.SECONDS.sleep(CommonConst.IndexCommitSeconds); // 睡眠
				 
				} catch (Exception e) {
					e.printStackTrace(); 
				}
				
			}
			super.run();
		}
	}

	// 获取TrackingIndexWriter
	public static TrackingIndexWriter getTrackingIndexWriter(){
		return trackingIndexWriter ;
	}
		
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
